﻿/**********************************************
DistortImage class
Availability
Flash Player 6.

Description
Tesselate a movieclip into several triangles
to allow free transform distorsion.

Method summary for the DistortImage class
getBounds - returns the original bounding box
setTransform - distort image by the passsed
rect coordinates.

###############################################
thanks to peter joel for his transformation
math code and thomas wagner for the basic idea.

(C) [url]http://www.andre-michelle.com[/url]
    free to use !
**********************************************/
package com.calefk.util {
    
    import flash.display.MovieClip;
    import flash.utils.*;
    
	public class DistortImage {
        
	      private var parent: MovieClip;
	      private var symbolId: String;

	      private var width: Number;
	      private var height: Number;

	      private var xMin: Number, xMax: Number, yMin: Number, yMax: Number;

	      private var hseg: Number;
	      private var vseg: Number;

	      private var hsLen: Number;
	      private var vsLen: Number;

	      private var points: Array;
	      private var triAngles: Array;

	      public function DistortImage( parent: MovieClip, symbolId: String, vseg: Number, hseg: Number )
	      {
	            this.parent = parent;
	            this.symbolId = symbolId;
	            this.vseg = vseg;
	            this.hseg = hseg;

	            if ( arguments.length > 4 )
	            {
	                  width = arguments[ 4 ];
	                  height = arguments[ 5 ];
	            }
	            else
	            {
	                  getImageSize();
	            }

	            init();
	      }

	      private function getImageSize()
	      {     var obClass:Class = getDefinitionByName(symbolId) as Class;
	            var getDimension:MovieClip = new obClass() as MovieClip;
	            width       = int( getDimension.width );
	            height      = int( getDimension.height );
	      }

	      private function init(): void
	      {
	            points = new Array();
	            triAngles = new Array();

	            var ix: Number;
	            var iy: Number;

	            var w2: Number = width / 2;
	            var h2: Number = height / 2;

	            hsLen = width / ( vseg + 1 );
	            vsLen = height / ( hseg + 1 );

	            var x: Number, y: Number;

	            for ( ix = 0 ; ix < vseg + 2 ; ix++ )
	            {
	                  for ( iy = 0 ; iy < hseg + 2 ; iy++ )
	                  {
	                        x = ix * hsLen;
	                        y = iy * vsLen;
	                        points.push( { x: x, y: y, sx: x, sy: y } );
	                  }
	            }

	            for ( ix = 0 ; ix < vseg + 1 ; ix++ )
	            {
	                  for ( iy = 0 ; iy < hseg + 1 ; iy++ )
	                  {
	                        createTriAngle( ix, iy, 1, [ points[ iy + ix * ( hseg + 2 ) ] , points[ iy + ix * ( hseg + 2 ) + 1 ] , points[ iy + ( ix + 1 ) * ( hseg + 2 ) ] ] );
	                        createTriAngle( ix, iy,-1, [ points[ iy + ( ix + 1 ) * ( hseg + 2 ) + 1 ] , points[ iy + ( ix + 1 ) * ( hseg + 2 ) ] , points[ iy + ix * ( hseg + 2 ) + 1 ] ] );
	                  }
	            }

	            xMin = yMin = 0;
	            xMax = width;
	            yMax = height;

	            render();
	      }

	      private function createTriAngle( x: Number, y: Number, align: Number, vertices: Array ): void
	      {
	            var n: Number;
	            var triAngle: MovieClip;

	            n = triAngles.length;

	            triAngle = new MovieClip();
                parent.addChild(triAngle);

                
	            var inner: MovieClip = new MovieClip();
                triAngle.inner = inner;
                triAngle.addChild(inner);
                
	            var mask : MovieClip = new MovieClip();
                mask.name = "mask";
                inner.addChild(mask);
                
                var objClass:Class = getDefinitionByName(symbolId) as Class;
                var image:MovieClip = new objClass() as MovieClip;
                inner.addChild(image);
                
	            inner.rotation = -45;
	            mask.graphics.beginFill( 0 );
	            mask.graphics.moveTo( -1 , -1 );
	            mask.graphics.lineTo( 101 , -1 );
	            mask.graphics.lineTo( -1 , 101 );
	            mask.graphics.lineTo( -1 , -1 );
	            mask.graphics.endFill();

	            triAngle.mask = mask ;

	            image.scaleX = (10000 / hsLen) / 100;
	            image.scaley = (10000 / vsLen) / 100;

	            if ( align == 1 )
	            {
	                  image.x = -x * 100;
	                  image.y = -y * 100;
	            }
	            else
	            {
	                  image.rotation = -180;
	                  image.x = ( x + 1 ) * 100;
	                  image.y = ( y + 1 ) * 100;
	            }

	            triAngle.vertices = vertices;
	            triAngles.push( triAngle );
	      }

	      public function setTransform( x0:Number , y0:Number , x1:Number , y1:Number , x2:Number , y2:Number , x3:Number , y3:Number ): void
	      {
	            var w:Number = width;
	            var h:Number = height;
	            var w2_0:Number = x1-x0;
	            var w2_1:Number = x2-x3;
	            var h2_0:Number = y1-y0;
	            var h2_1:Number = y2-y3;

	            for ( var p:int = 0 ; p < points.length; p++)
	            {
	                  var point:Object = points[p];

	                  var gx:Number = ( point.x - xMin ) / w;
	                  var gy:Number = ( point.y - yMin ) / h;
	                  var bx:Number = x0 + gy * ( x3 - x0 );
	                  var by:Number = y0 + gy * ( y3 - y0 );

	                  point.sx = bx + gx * ( ( x1 + gy * ( x2 - x1 ) ) - bx );
	                  point.sy = by + gx * ( ( y1 + gy * ( y2 - y1 ) ) - by );
	            }

	            render();
	      }

	      private function render(): void
	      {
	            // var t: Number;
	            var tmc: MovieClip;
	            var inner: MovieClip;
	            var vertices: Array;
	            var p0, p1, p2;

	            var atan2: Function = Math.atan2;
	            var sqrt: Function = Math.sqrt;
	            var cos: Function = Math.cos;
	            var tan: Function = Math.tan;

	            var arm,p0x,p0y,dx10,dy10,dx20,dy20,ap1,ap2,da12;

	            for (var t:int = 0; t < triAngles.length; t++)
	            {
	                  tmc = triAngles[t];

	                  inner = tmc.inner;
                      
	                  vertices = tmc.vertices;

	                  p0 = vertices[0];
	                  p1 = vertices[1];
	                  p2 = vertices[2];

	                  tmc.rotation = (180/Math.PI)*(-(da12=((ap1=atan2(dy10=p1.sy-(p0y=tmc.y=p0.sy),dx10=p1.sx-(p0x=tmc.x=p0.sx)))-(ap2=atan2(dy20=p2.sy-p0y,dx20=p2.sx-p0x)))/2)+ap1);
	                  tmc.scaleY = tan( da12 );
	                  inner.scaleX = sqrt(dx20*dx20+dy20*dy20)/(arm=100/(Math.SQRT1_2 * 2)/cos(da12));
	                  inner.scaleY = sqrt(dx10*dx10+dy10*dy10)/arm;
	            }
	      }

	      public function getBounds(): Object
	      {
	            return { xMin: xMin, xMax: xMax, yMin: yMin, yMax: yMax };
	      }
	} 

}